package bz.ziro.kanbe.dao;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.slim3.datastore.Datastore;

import com.google.appengine.api.datastore.Key;

import bz.ziro.kanbe.bean.Pager;
import bz.ziro.kanbe.meta.PageMeta;
import bz.ziro.kanbe.model.Page;
import bz.ziro.kanbe.model.Site;
import bz.ziro.kanbe.util.KeyFactory;

/**
 * ページ検索
 * @author Administrator
 *
 */
public class PageDao extends BaseDao<Page> {

	/**
	 * メタデータ
	 */
    private static final PageMeta pageMeta = new PageMeta();

    @SuppressWarnings("unused")
    private static final Logger logger = Logger.getLogger(PageDao.class.getName());

    /**
     * ページ１件検索
     * @param aSiteKey
     * @param aKey
     * @return
     */
    public static Page find(Long aSiteKey, Long aKey) {
        Key key = KeyFactory.createPageKey(aSiteKey,aKey);
        return Datastore.query(pageMeta)
        			.filter(
        				pageMeta.key.equal(key)
        			).asSingle();
    }

    /**
     * 削除
     * @param aSiteKey
     * @param aKey
     */
    public static void delete(Long aSiteKey,Long aKey) {

        Page page = find(aSiteKey,aKey);
        int priority = page.getPriority();

        //高い優先度のページを検索
        List<Page> pageList = findHighPriotity(priority,page.getParentPageKey());
        //ページリスト数回繰り返す
        for ( Page wkPage : pageList ) {
        	//ページ分の優先度を下げる
            wkPage.setPriority(wkPage.getPriority()-1);
        }
        //存在した場合
        if ( pageList != null && pageList.size() > 0 ) {
        	//更新をかける
            Datastore.put(pageList);
        }
        //ページを削除する
        Datastore.delete(page.getKey());
    }

    /**
     * 指定優先順位より高いデータを取得
     * @param priority
     * @param key
     * @return
     */
    private static List<Page> findHighPriotity(int priority, Key key) {
        return Datastore.query(pageMeta)
        		.filter(
        			pageMeta.priority.greaterThan(priority),
        			pageMeta.parentPageKey.equal(key)
        		).asList();
    }

    /**
     * サイト内のページを全件取得
     * @param siteKey
     * @return
     */
    public static List<Page> all(Long siteKey) {
        Key key = KeyFactory.createSiteKey(siteKey);
        return Datastore.query(pageMeta)
        		.filter(
        			pageMeta.siteKey.equal(key)
        		).asList();
    }

    /**
     * サイトの先頭ページを取得
     * @param site
     * @return
     */
    public static Page findRootPage(Site site) {
        return Datastore.query(pageMeta)
        		.filter(
                    pageMeta.parentPageKey.equal(null),
            		pageMeta.siteKey.equal(site.getKey())
           		).asSingle();
    }

    /**
     * ページリストを取得
     * @param key
     * @param num
     * @param paging
     * @return
     */
    public static List<Page> findParentList(Key key, int num, int paging) {
        //件数からオフセットを取得
        int offset = (paging - 1) * num;
        return Datastore.query(pageMeta)
        		.filter(
        			pageMeta.parentPageKey.equal(key)
        		).offset(offset).limit(num)
        		.sort(pageMeta.priority.desc).asList();
    }

    /**
     * 公開サイトのページを取得
     * @param aKey
     * @return
     */
    public static Page findPublishPage(Long aKey) {
        //TODO テストページ用には別で作る
        Site site = SiteDao.findPublish();
        Key key = KeyFactory.createPageKey(site.getKey().getId(),aKey);
        return Datastore.query(pageMeta)
        		.filter(
        			pageMeta.key.equal(key)
        		).asSingle();
    }

    /**
     * 優先順位を評価して更新する
     * @param pageList
     */
    public static void updatePriority(List<Page> pageList) {

        //しっかり優先順位がついてない場合
        if ( !isUniquePriority(pageList) ) {
            //リスト数回繰り返す
            for ( int cnt = 0; cnt < pageList.size(); ++cnt ) {
                Page page = pageList.get(cnt);
                page.setPriority(cnt+1);
            }
            //すべて設定して更新する
            Datastore.put(pageList);
        }
    }

    /**
     * 優先順位がしっかりついているか？
     * @param pageList
     * @return
     */
    private static boolean isUniquePriority(List<Page> pageList) {

        Map<Integer,Page> pageMap = new HashMap<Integer,Page>();
        Integer max = pageList.size();
        //ページ数回繰り返す
        for ( Page page : pageList ) {
            Integer priority = page.getPriority();
            //存在しないもしくは範囲外の場合
            if ( priority == null || priority <= 0 || priority > max ) {
                return false;
            }
            //マップに存在する場合
            if ( pageMap.containsKey(priority) ) {
                return false;
            }
            pageMap.put(priority, page);
        }
        return true;
    }

    /**
     * 同じ階層のデータの件数を取得
     * @param key
     * @return
     */
    public static int findParentCount(Key key) {
        return Datastore.query(pageMeta)
        		.filter(
        			pageMeta.parentPageKey.equal(key)
        		).count();
    }

    /**
     * ページャを生成
     * @param aNum 
     * @param parentPageKey
     * @param aNum
     * @return
     */
	public static Pager createPagePager(Key pageKey,String pageNum,int aLimit) {
		//キーを親に持つデータ数を取得
		Integer count = findParentCount(pageKey);
		Pager pager = new Pager(count,pageNum,aLimit);
		return pager;
	}
}
